package chen.videoedit;


import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMuxer;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;

/**
 * Created by 15705 on 2018/3/7.
 * Android Api视频拼接
 */
@TargetApi(18)
public class VideoComposer {
    private ArrayList<String> mVideoList;
    private String mOutFilename;

    private MediaMuxer mMuxer;
    private ByteBuffer mReadBuf;
    private int mOutAudioTrackIndex;//
    private int mOutVideoTrackIndex;
    private MediaFormat mAudioFormat;
    private MediaFormat mVideoFormat;

    public VideoComposer(ArrayList<String> videoList, String outFilename) {
        mVideoList = videoList;
        this.mOutFilename = outFilename;
        mReadBuf = ByteBuffer.allocate(1048576);
    }

    @SuppressLint("WrongConstant")
    public boolean joinVideo() {
        boolean getAudioFormat = false;
        boolean getVideoFormat = false;
        Iterator videoIterator = mVideoList.iterator();
        //遍历媒体文件获取格式
        while (videoIterator.hasNext()) {
            String videoPath = (String) videoIterator.next();
            MediaExtractor extractor = new MediaExtractor();
            try {
                extractor.setDataSource(videoPath);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            //视频格式获取
            int trackIndex;
            if (!getVideoFormat) {
                trackIndex = this.selectTrack(extractor, "video/");
                if (trackIndex < 0) {
                } else {
                    extractor.selectTrack(trackIndex);
                    mVideoFormat = extractor.getTrackFormat(trackIndex);
                    getVideoFormat = true;
                }
            }
            //音频格式获取
            if (!getAudioFormat) {
                trackIndex = this.selectTrack(extractor, "audio/");
                if (trackIndex < 0) {
                } else {
                    extractor.selectTrack(trackIndex);
                    mAudioFormat = extractor.getTrackFormat(trackIndex);
                    getAudioFormat = true;
                }
            }
            extractor.release();
            if (getVideoFormat && getAudioFormat) {
                break;
            }
        }
        //初始化媒体混合器
        try {
            mMuxer = new MediaMuxer(this.mOutFilename, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (getVideoFormat) {
            mOutVideoTrackIndex = mMuxer.addTrack(mVideoFormat);//添加视频格式
        }
        if (getAudioFormat) {
            mOutAudioTrackIndex = mMuxer.addTrack(mAudioFormat);//添加音轨格式
        }
        mMuxer.start();


        long ptsOffset = 0L;//多个视频累计时间
        Iterator trackIndex = mVideoList.iterator();
        while (trackIndex.hasNext()) {
            String videoPath = (String) trackIndex.next();
            boolean hasVideo = true;
            boolean hasAudio = true;


            //媒体文件视频提取器
            MediaExtractor videoExtractor = new MediaExtractor();
            try {
                videoExtractor.setDataSource(videoPath);
            } catch (Exception var27) {
                var27.printStackTrace();
            }
            int inVideoTrackIndex = this.selectTrack(videoExtractor, "video/");
            if (inVideoTrackIndex < 0) {
                hasVideo = false;
            }
            videoExtractor.selectTrack(inVideoTrackIndex);

            //媒体文件音频提取器
            MediaExtractor audioExtractor = new MediaExtractor();
            try {
                audioExtractor.setDataSource(videoPath);
            } catch (Exception e) {
                e.printStackTrace();
            }
            int inAudioTrackIndex = this.selectTrack(audioExtractor, "audio/");
            if (inAudioTrackIndex < 0) {
                hasAudio = false;
            }
            audioExtractor.selectTrack(inAudioTrackIndex);


            boolean bMediaDone = false;
            long presentationTimeUs = 0L;
            long audioPts = 0L;
            long videoPts = 0L;

            while (!bMediaDone) {
                if (!hasVideo && !hasAudio) break;//检查 音轨 视频是否正确


                int outTrackIndex;//当期处理的媒体混合轨道
                MediaExtractor extractor;
                int currenttrackIndex;
                if ((!hasVideo || audioPts - videoPts <= 50000L) && hasAudio) {//文件没有视频轨道
                    currenttrackIndex = inAudioTrackIndex;
                    outTrackIndex = mOutAudioTrackIndex;
                    extractor = audioExtractor;
                } else {
                    currenttrackIndex = inVideoTrackIndex;
                    outTrackIndex = mOutVideoTrackIndex;
                    extractor = videoExtractor;
                }

                mReadBuf.rewind();
                int chunkSize = extractor.readSampleData(mReadBuf, 0);//读取帧数据
                if (chunkSize < 0) {//是否读取完成
                    if (currenttrackIndex == inVideoTrackIndex) {
                        hasVideo = false;
                    } else if (currenttrackIndex == inAudioTrackIndex) {
                        hasAudio = false;
                    }
                } else {


                    presentationTimeUs = extractor.getSampleTime();//读取帧的pts （显示时间）
                    if (currenttrackIndex == inVideoTrackIndex) {
                        videoPts = presentationTimeUs;
                    } else {
                        audioPts = presentationTimeUs;
                    }

                    BufferInfo info = new BufferInfo();
                    info.offset = 0;
                    info.size = chunkSize;
                    info.presentationTimeUs = ptsOffset + presentationTimeUs;//pts重新计算
                    if ((extractor.getSampleFlags() & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0) {
                        info.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
                    }

                    mReadBuf.rewind();
                    mMuxer.writeSampleData(outTrackIndex, mReadBuf, info);//写入文件
                    extractor.advance();
                }
            }

            //记录当前文件的最后一个pts，作为下一个文件的pts offset
            ptsOffset += videoPts > audioPts ? videoPts : audioPts;
            ptsOffset += 10000L;//前一个文件的最后一帧与后一个文件的第一帧，差10ms，只是估计值，不准确，但能用


            videoExtractor.release();
            audioExtractor.release();
        }

        if (mMuxer != null) {
            try {
                mMuxer.stop();
                mMuxer.release();
            } catch (Exception e) {
            }

            mMuxer = null;
        }

        return true;
    }

    private int selectTrack(MediaExtractor extractor, String mimePrefix) {
        int numTracks = extractor.getTrackCount();

        for (int i = 0; i < numTracks; ++i) {
            MediaFormat format = extractor.getTrackFormat(i);
            String mime = format.getString("mime");
            if (mime.startsWith(mimePrefix)) {
                return i;
            }
        }

        return -1;
    }
}
